#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
民族识别配置模块
包含56个中国民族的识别和OCR错误纠正
"""

import json
import os
import re
from typing import Dict, List, Optional, Tuple
from difflib import SequenceMatcher


class EthnicityMatcher:
    """民族匹配器"""
    
    def __init__(self):
        """初始化民族匹配器"""
        self.ethnicity_data = self._load_ethnicity_data()
        self.card_display_map = self._build_card_display_map()
        self.ocr_error_map = self._build_ocr_error_map()
        
    def _load_ethnicity_data(self) -> Dict:
        """加载民族数据"""
        try:
            current_dir = os.path.dirname(os.path.abspath(__file__))
            config_path = os.path.join(current_dir, 'ethnicity_comparison.json')
            
            with open(config_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"加载民族配置失败: {e}")
            return self._get_default_ethnicity_data()
    
    def _build_card_display_map(self) -> Dict[str, str]:
        """构建身份证显示形式到官方名称的映射"""
        display_map = {}
        
        for ethnicity, info in self.ethnicity_data.get('ethnicity_groups', {}).items():
            card_display = info.get('card_display', '')
            official_name = info.get('official_name', ethnicity)
            
            if card_display:
                display_map[card_display] = official_name
                
            # 添加变体映射
            for variant in info.get('variants', []):
                if variant != official_name:  # 避免重复映射
                    display_map[variant] = official_name
        
        return display_map
    
    def _build_ocr_error_map(self) -> Dict[str, str]:
        """构建OCR错误到正确民族名的映射"""
        error_map = {}
        
        for correct_name, error_list in self.ethnicity_data.get('common_ocr_errors', {}).items():
            for error_name in error_list:
                if error_name != correct_name:  # 避免自映射
                    error_map[error_name] = correct_name
        
        return error_map
    
    def _get_default_ethnicity_data(self) -> Dict:
        """获取默认民族数据（防备配置文件加载失败）"""
        return {
            "ethnicity_groups": {
                "汉族": {"official_name": "汉族", "card_display": "汉", "variants": ["汉", "汉族"]},
                "壮族": {"official_name": "壮族", "card_display": "壮", "variants": ["壮", "壮族"]},
                "满族": {"official_name": "满族", "card_display": "满", "variants": ["满", "满族"]},
                "回族": {"official_name": "回族", "card_display": "回", "variants": ["回", "回族"]},
                "苗族": {"official_name": "苗族", "card_display": "苗", "variants": ["苗", "苗族"]},
                "维吾尔族": {"official_name": "维吾尔族", "card_display": "维吾尔", "variants": ["维吾尔", "维吾尔族"]},
                "土家族": {"official_name": "土家族", "card_display": "土家", "variants": ["土家", "土家族"]},
                "彝族": {"official_name": "彝族", "card_display": "彝", "variants": ["彝", "彝族"]},
                "蒙古族": {"official_name": "蒙古族", "card_display": "蒙古", "variants": ["蒙古", "蒙古族"]},
                "藏族": {"official_name": "藏族", "card_display": "藏", "variants": ["藏", "藏族"]}
            },
            "common_ocr_errors": {
                "汉": ["讥", "汇", "汁"],
                "蒙古": ["蒙后", "蒙右", "豪古"],
                "维吾尔": ["维乌尔", "雏吾尔", "推吾尔"]
            }
        }
    
    def match_ethnicity(self, text: str) -> Optional[str]:
        """
        匹配民族名称
        
        Args:
            text: 待匹配的文本
            
        Returns:
            匹配到的民族名称（身份证显示形式，不带"族"字）
        """
        if not text:
            return None
        
        # 清理文本
        text = text.strip()
        
        # 1. 直接匹配身份证显示形式
        result = self._direct_match(text)
        if result:
            return result
        
        # 2. OCR错误纠正匹配
        result = self._ocr_error_match(text)
        if result:
            return result
        
        # 3. 模糊匹配
        result = self._fuzzy_match(text)
        if result:
            return result
        
        # 4. 编辑距离匹配
        result = self._edit_distance_match(text)
        if result:
            return result
        
        return None
    
    def _direct_match(self, text: str) -> Optional[str]:
        """直接匹配"""
        # 从文本中提取民族相关内容
        patterns = [
            r'民族\s*[:：]?\s*([\u4e00-\u9fff]+?)(?=\s|$|[0-9]|住址|出生|年|族)',
            r'民族\s*([\u4e00-\u9fff]+?)(?=\s|$|[0-9]|住址|出生|年|族)',
            r'民族([\u4e00-\u9fff]+?)(?=\s|$|[0-9]|住址|出生|年|族)',
        ]
        
        for pattern in patterns:
            matches = re.findall(pattern, text)
            for match in matches:
                match = match.strip()
                # 先尝试直接匹配
                if match in self.card_display_map:
                    official_name = self.card_display_map[match]
                    return self._get_card_display_form(official_name)
                # 尝试去掉"族"字匹配
                elif match.endswith('族') and match[:-1] in self.card_display_map:
                    official_name = self.card_display_map[match[:-1]]
                    return self._get_card_display_form(official_name)
        
        # 检查整个文本是否匹配
        if text in self.card_display_map:
            official_name = self.card_display_map[text]
            return self._get_card_display_form(official_name)
        
        return None
    
    def _ocr_error_match(self, text: str) -> Optional[str]:
        """OCR错误匹配"""
        if text in self.ocr_error_map:
            correct_name = self.ocr_error_map[text]
            if correct_name in self.card_display_map:
                official_name = self.card_display_map[correct_name]
                return self._get_card_display_form(official_name)
        
        return None
    
    def _fuzzy_match(self, text: str, threshold: float = 0.8) -> Optional[str]:
        """模糊匹配"""
        best_match = None
        best_score = 0
        
        for display_name in self.card_display_map.keys():
            if len(display_name) <= 1:  # 跳过单字符匹配，避免误匹配
                continue
                
            score = SequenceMatcher(None, text, display_name).ratio()
            if score > threshold and score > best_score:
                best_score = score
                best_match = display_name
        
        if best_match:
            official_name = self.card_display_map[best_match]
            return self._get_card_display_form(official_name)
        
        return None
    
    def _edit_distance_match(self, text: str, max_distance: int = 1) -> Optional[str]:
        """编辑距离匹配"""
        def edit_distance(s1: str, s2: str) -> int:
            if len(s1) > len(s2):
                s1, s2 = s2, s1
            
            distances = range(len(s1) + 1)
            for i2, c2 in enumerate(s2):
                distances_ = [i2 + 1]
                for i1, c1 in enumerate(s1):
                    if c1 == c2:
                        distances_.append(distances[i1])
                    else:
                        distances_.append(1 + min((distances[i1], distances[i1 + 1], distances_[-1])))
                distances = distances_
            return distances[-1]
        
        best_match = None
        best_distance = max_distance + 1
        
        for display_name in self.card_display_map.keys():
            # 只对长度相近的进行编辑距离计算
            if abs(len(text) - len(display_name)) <= max_distance:
                distance = edit_distance(text, display_name)
                if distance <= max_distance and distance < best_distance:
                    best_distance = distance
                    best_match = display_name
        
        if best_match:
            official_name = self.card_display_map[best_match]
            return self._get_card_display_form(official_name)
        
        return None
    
    def _get_card_display_form(self, official_name: str) -> str:
        """获取身份证显示形式（不带"族"字）"""
        for ethnicity_info in self.ethnicity_data.get('ethnicity_groups', {}).values():
            if ethnicity_info.get('official_name') == official_name:
                return ethnicity_info.get('card_display', official_name.replace('族', ''))
        
        # 备用：直接去掉"族"字
        return official_name.replace('族', '')
    
    def get_all_ethnicities(self) -> List[str]:
        """获取所有民族的身份证显示形式"""
        return [info.get('card_display', name.replace('族', '')) 
                for name, info in self.ethnicity_data.get('ethnicity_groups', {}).items()]
    
    def get_ethnicity_info(self, ethnicity_name: str) -> Optional[Dict]:
        """获取民族详细信息"""
        for name, info in self.ethnicity_data.get('ethnicity_groups', {}).items():
            if (info.get('card_display') == ethnicity_name or 
                info.get('official_name') == ethnicity_name or
                ethnicity_name in info.get('variants', [])):
                return info
        return None


# 全局实例
ethnicity_matcher = EthnicityMatcher()


def match_ethnicity(text: str) -> Optional[str]:
    """
    匹配民族名称的便捷函数
    
    Args:
        text: 待匹配的文本
        
    Returns:
        匹配到的民族名称（身份证显示形式）
    """
    return ethnicity_matcher.match_ethnicity(text)


def get_all_ethnicities() -> List[str]:
    """获取所有56个民族的身份证显示形式"""
    return ethnicity_matcher.get_all_ethnicities()


if __name__ == "__main__":
    # 测试代码
    test_cases = [
        "民族 汉",
        "民族：满", 
        "民族 蒙古",
        "民族 维吾尔",
        "民族 壮",
        "民族回",
        "汉",
        "满",
        "蒙古",
        "维吾尔", 
        "壮",
        # OCR错误测试
        "蒙后",  # 蒙古的OCR错误
        "维乌尔",  # 维吾尔的OCR错误
        "壯",  # 壮的繁体
    ]
    
    print("=== 民族识别测试 ===")
    for test_text in test_cases:
        result = match_ethnicity(test_text)
        print(f"'{test_text}' -> '{result}'")
    
    print(f"\n共支持 {len(get_all_ethnicities())} 个民族")
    print("前10个民族:", get_all_ethnicities()[:10])